const { ApiPromise, WsProvider } = require('@polkadot/api');
const { Keyring } = require('@polkadot/keyring');
const { decodeAddress } = require('@polkadot/util-crypto');

// 连接波卡测试网节点
async function createApi() {
    // Initialise the provider to connect to the local node
    const provider = new WsProvider('ws://192.168.0.200:8866');
    // Create the API and wait until ready
    const api = await ApiPromise.create({ provider });
    return api;
}

// 初始化账户
function initKeyring(privateKey) {
    const keyring = new Keyring({ type: 'ethereum' });
    const account = keyring.addFromUri(privateKey); // 测试网默认账户
    return account;
}

// 查询 Chain State
async function queryChainState(api) {
    // 查询区块高度
    const block_height = await api.query.system.number();
    console.log(`当前区块高度: ${block_height}`);

    // 查询账户余额
    const account = '0x2495E6a0e135A27031FC758917D84A4c0B139F10';
    const accountInfo = await api.query.system.account(account);
    console.log(`账户信息：${accountInfo}`);
}

// 调用 RPC
async function callRpc(api) {
    // 获取最新区块哈希
    const blockHash = await api.rpc.chain.getBlockHash();
    console.log('最新区块哈希:', blockHash.toHex());

    // 获取节点版本
    const version = await api.rpc.system.version();
    console.log('节点版本:', version.toHuman());

    // 查询链ID
    const chainId = await api.rpc.eth.chainId();
    console.log(`链的id信息: ${chainId}`);
}

async function payoutStakers(api, sender, validatorAddr, eraIndex) {
    // 构造 payoutStakers 交易
    const payoutTx = api.tx.staking.payoutStakers(validatorAddr, eraIndex);

    // 发送交易并监听状态
    const unsub = await payoutTx.signAndSend(sender, ({ events = [], status }) => {
        if (status.isInBlock) {
            console.log(`交易已打包在区块: ${status.asInBlock.toHex()}`);
            events.forEach(({ event }) => {
                if (event.method === "Rewarded") {
                    console.log("奖励分发成功:", event.data.toHuman());
                } else if (event.method === "ExtrinsicFailed") {
                    console.error("交易失败:", event.data.toHuman());
                }
            });
            unsub();
        }
    });
    console.log("交易已提交，等待打包...");
}

async function payout(api, account, validator, era) {
    const tx = api.tx.staking.payoutStakers(validator, era);
    return new Promise((resolve) => {
        tx.signAndSend(account, ({ status }) => {
            if (status.isInBlock) {
                console.log(`✅ 支付成功，Era ${era} 验证人 ${validator} 在区块 ${status.asInBlock}`);
                resolve();
            }
        }).catch((error) => {
            console.error('❌ 支付失败:', error);
            resolve();
        });
    });
}

async function processEras_demo(api, account) {
    // 获取历史深度
    const historyDepth = (await api.consts.staking.historyDepth).toNumber();
    console.log(`historyDepth Era: ${historyDepth}`);

    // 获取当前活跃 Era
    const activeEra = await api.query.staking.activeEra();
    const currentEra = activeEra.unwrap().index.toNumber();
    console.log(`当前活跃 Era: ${currentEra}`);

    // 查询验证者列表
    const validators = await api.query.staking.allowValidators();
    console.log(`validators: ${validators}`);

    validators.forEach((validator, index)=> {
        console.log(`index: ${index}, validator: ${validator}`);
    });

    // 检查是否已支付
    const eraIndex = 10;
    const validator = '0xE15aca936a47FeAfc8a80B01f57c9f5e7e966666';
    // const validator = api.createType('AccountId', '0xE15aca936a47FeAfc8a80B01f57c9f5e7e966666');
    // const validator = decodeAddress('0xE15aca936a47FeAfc8a80B01f57c9f5e7e966666');
    const claimed = await api.query.staking.claimedRewards(eraIndex, validator);
    // console.log(`claimed: ${claimed}`);
    if (claimed.isEmpty) {
        console.log(`era${eraIndex}周期未支付，现进行支付。。。`);
        await payoutStakers(api, account, validator, eraIndex);
    } else {
        console.log(`账户${validator}已支付era${eraIndex}周期的奖励`);
    }
}

async function processEras(api, account) {
    // 获取当前活跃 Era
    const activeEra = await api.query.staking.activeEra();
    const currentEra = activeEra.unwrap().index.toNumber();
    console.log(`当前活跃 Era: ${currentEra}`);

    // 获取历史深度
    const historyDepth = (await api.consts.staking.historyDepth).toNumber();
    console.log(`historyDepth Era: ${historyDepth}`);

    // 计算开始 Era
    let startEra = 0;
    if (currentEra < historyDepth) {
        startEra = 0;
    } else {
        startEra = currentEra - historyDepth;
    }
    console.log(`startEra: ${startEra}`);
    // 检查是否已支付
    for (let era = startEra; era < currentEra; era++) {
        // 查询验证者列表
        const validators = await api.query.staking.allowValidators();
        for (const validator of validators) {
            const claimed = await api.query.staking.claimedRewards(era, validator);
            if (claimed.isEmpty) {
              console.log(`❗ 发现未支付: Era ${era}, 验证人 ${validator}`);
              await payout(api, account, validator, era);
            }
        }
    }
}

// 辅助函数：加载 WASM 文件
async function loadWasmFile(filePath) {
    const buffer = await fs.readFile(filePath);
    return '0x' + buffer.toString('hex');
}

async function sudoUpgradeRuntime(api, sudoAccount) {
    // 加载 WASM 文件
    const wasmHex = await loadWasmFile('./runtime.compact.wasm');
    // 构造升级提案
    const proposal = api.tx.system.setCode(wasmHex);
     // 使用 sudo 包装
    const sudoTx = api.tx.sudo.sudo(proposal);
    // 发送sudo交易
    return new Promise((resolve) => {
        sudoTx.signAndSend(sudoAccount, ({ status }) => {
            if (status.isInBlock) {
                console.log(`✅交易已打包在区块 ${status.asInBlock}`);
                resolve();
            }
            if (status.isFinalized) {
                console.log(`💯交易最终确认在区块 ${status.asFinalized}`);
                process.exit(0);
              }
        }).catch((error) => {
            console.error('更改失败:', error);
            resolve();
        });
    });
}

async function sudoOperation(api, sudoAccount) {
    // 构造需要 sudo 权限的调用（示例：升级运行时）
    // const proposal = api.tx.system.setCode('0x...编译后的Wasm字节码...');
      // 使用 sudo.sudo 包装调用
    // const sudoTx = api.tx.sudo.sudo(proposal);

    const newValidatorCount = 5;
    const proposal = api.tx.staking.setValidatorCount(newValidatorCount);
    const sudoTx = api.tx.sudo.sudo(proposal);

    // 发送sudo交易
    return new Promise((resolve) => {
        sudoTx.signAndSend(sudoAccount, ({ status }) => {
            if (status.isInBlock) {
                console.log(`✅ 交易已打包在区块 ${status.asInBlock}`);
            }
            if (status.isFinalized) {
                console.log(`💯 交易最终确认在区块 ${status.asFinalized}`);
                process.exit(0);
            }
        }).catch((error) => {
            console.error('更改失败:', error);
            resolve();
        });
    });

    // sudoTx.signAndSend(sudoAccount, { nonce: -1 }, ({ status, events }) => {
    //     if (status.isInBlock) {
    //       console.log(`✅ 交易已打包在区块 ${status.asInBlock}`);
    //     }
    //     if (status.isFinalized) {
    //       console.log(`💯 交易最终确认在区块 ${status.asFinalized}`);
    //       process.exit(0);
    //     }
    //   });
}

async function main() {
    const api = await createApi();
    const privateKey = '0x035a2cba54dbc6404cd2b9262aabcdc12e338f1387045452672834b34ca8e246';
    const account = initKeyring(privateKey);
  
    // console.log("执行 Chain State 板块查询。。。")
    // await queryChainState(api);

    // console.log("执行 Rpc calls 板块查询。。。")
    // await callRpc(api);
    
    // console.log("执行 EXtrinsics 板块查询。。。")
    // const validatorAddr = '0xE15aca936a47FeAfc8a80B01f57c9f5e7e966666';
    // const eraIndex = 8;
    // await payoutStakers(api, account, validatorAddr, eraIndex);
    
    // 循环执行era奖励
    await processEras(api, account);
   

    // console.log("执行 sudo 板块查询。。。")
    // const sudoPrivateKey = '0x035a2cba54dbc6404cd2b9262aabcdc12e338f1387045452672834b34ca8e246'
    // const sudoAccount = initKeyring(sudoPrivateKey)
    // await sudoOperation(api, sudoAccount); // 需确sudo账户（测试网可能无权限）
}
  

main()
.then(() => process.exit(0))
.catch((error) => {
    console.error(error);
    process.exit(1);
});

// main().catch(console.error);
// main().catch(console.error).finally(() => process.exit());